#include "DeductionController.h"

#include "windows.h"

#include <algorithm>
#include <boost/bind.hpp>

using namespace Controllers;

DeductionController::DeductionController(Views::IDeductionView* view, Utils::Logging::ILogger* logger,
	Players::Player* player, Players::PlayersQueue players, Cards::CardsCollection cards)
	: view(view), current_player(player), players(players), cards(cards), deducted_card(NULL)
{
	this->logger = logger;

	connectEvent<void (Cards::PlayerCard*, Cards::WeaponCard*)>(view->searchedCardsPickEvent,
		boost::bind(&DeductionController::setSearchedCards, this, _1, _2));
	connectEvent<void ()>(this->onSearchedCardsChange, boost::bind(&DeductionController::askOtherPlayersForSearchedCards, this));
	connectEvent<void (Cards::Card*)>(view->deductedCardPickEvent,
		boost::bind(&DeductionController::setDeductedCard, this, _1));
	connectEvent<void ()>(this->onDeductedCardChange, boost::bind(&DeductionController::cardFound, this));
	connectEvent<void ()>(view->deductedCardsShowEvent, boost::bind(&DeductionController::deductionPerformed, this));

	players.pop();
}

void DeductionController::perform()
{
	askCurrentPlayerForSearchedCards();
}

void DeductionController::askCurrentPlayerForSearchedCards()
{
	view->openPickSearchedCardsDialog(current_player, cards.getPlayersCards(), cards.getWeaponsCards());
}

void DeductionController::setSearchedCards(Cards::PlayerCard* player, Cards::WeaponCard* weapon)
{
	searched_cards.add(player);
	searched_cards.add(weapon);
	searched_cards.add(findActualRoom());
	logger->deductionAskPlayersForCards(searched_cards);
	onSearchedCardsChange();
}

void DeductionController::askOtherPlayersForSearchedCards()
{
	askNextPlayerForSearchedCards();
}

void DeductionController::setDeductedCard(Cards::Card* card)
{
	deducted_card = card;
	onDeductedCardChange();
}

Cards::RoomCard* DeductionController::findActualRoom()
{
	Cards::RoomsCards room_cards = cards.getRoomsCards();
	for (Cards::RoomsCards::iterator i = room_cards.begin(); i != room_cards.end(); ++i)
	{
		if (*((*i)->room) == *(current_player->piece->room))
		{
			return *i;
		}
	}
	return NULL;
}

void DeductionController::askNextPlayerForSearchedCards()
{
	players.pop();
	if (players.empty())
	{
		setDeductedCard(NULL);
		return;
	}

	Players::Player* player = players.front();

	Cards::CardSet common_cards = player->getCards().intersect(searched_cards);

	if (common_cards.size() == 0)
	{
		askNextPlayerForSearchedCards();
	} else if (common_cards.size() == 1) {
		setDeductedCard(*(common_cards.begin()));
	} else {
		view->openPickCardDialog(player, common_cards);
	}
}

void DeductionController::cardFound()
{
	if (deducted_card == NULL)
	{
		view->showNoCardsDeducted(searched_cards, current_player);
		logger->deductionShowNoCardsDeducted();
	}
	else
	{
		view->showDeductedCard(deducted_card, current_player, players.front());
		logger->deductionShowDeductedCard(players.front());
	}
}


void DeductionController::deductionPerformed()
{
	deductionPerformedEvent();
}

